/**
 * Created by Administrator on 2016/11/9.
 */
import com.sun.media.sound.FFT;
import com.sun.org.apache.xerces.internal.impl.xpath.regex.Match;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.List;

public class main {

    public  static Complex[] fft(Complex[] y){
        bit_reverse(y);
        int j, k, h;
        for (h = 2; h <= y.length; h <<= 1) {
            // twiddle factor 旋转因子
            Complex omega_n=new Complex(Math.cos(-2* Math.PI/h),Math.sin(-2*Math.PI/h));

            for (j = 0; j < y.length; j += h) {
                Complex omega = new Complex(1, 0);
                // butterfly transformation
                for (k = j; k < j + h / 2; ++k) {
                    Complex  u = y[k];
                    Complex  t = omega.mul(y[k + h / 2]);
                    y[k] = u.add(t);
                    y[k + h/2] = u.sub(t);
                    omega = omega.mul(omega_n);
                }
            }
        }
        return y;
    }
    public static void bit_reverse(Complex[] y) {
        int i, j, k;
        for (i = 1, j = y.length / 2; i < y.length - 1; ++i) {
            if (i < j) {
                Complex temp = y[i];
                y[i] = y[j];
                y[j] = temp;
            }
            k = y.length / 2;
            while (j >= k) {
                j -= k;            // eliminate leading 1.
                k /= 2;
                if (k == 0)        // cutting branches.
                    break;
            }
            if (j < k)             // add leading 1.
                j += k;
        }
    }


    public static final int WINDOW_SIZE = 4096;
    public static double[] fft(double[] slice) {

        Complex[] x = new Complex[WINDOW_SIZE];

        /**
         * Convert the time-domain series as Complex series whose imaginary parts are zeros.
         */
        for (int i = 0; i < WINDOW_SIZE; ++i) {
            x[i] = new Complex(slice[i], 0);
        }

        Complex[] res = fft(x);

        double[] ret = new double[WINDOW_SIZE];
        for (int i = 0; i < WINDOW_SIZE; ++i) {
            /**
             * The magnitude of each frequency.
             */
            ret[i] = res[i].abs();
        }
        return ret;
    }//通过double数组实现傅里叶时域转换频域
    public static double[] bytesToDouble(short[] s){
        int count=s.length;
        double[] db=new double[count];
        for(int i=0;i<count;i++)
        {
            db[i]=s[i];
        }
        return db;
    }//获取double数组
    public static short[] getShort(byte[] b){
        short[]sa=new short[b.length/2];
        ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(sa);
        return sa;
    }//获取short数组
    public static byte[] toByteArray(File f) throws IOException{
        //File f=new File(filename);
        if(!f.exists()){
            throw new FileNotFoundException(f.getName());
        }
        FileChannel channel=null;
        FileInputStream fs=null;
        try{
            fs=new FileInputStream(f);
            channel=fs.getChannel();
            ByteBuffer byteBuffer=ByteBuffer.allocate((int) channel.size());
            while ((channel.read(byteBuffer))>0){

            }

            return byteBuffer.array();
        }catch (IOException e){
            e.printStackTrace();
            throw e;
        }finally {
            try {
                channel.close();
            }catch (IOException e){
                e.printStackTrace();
            }
            try{
                fs.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }//获取byte数组
    public static int toInt(byte[]b){
        return ((b[0]<<0)+(b[1]<<8)+(b[2]<<16)+(b[3]<<24));

    }
    public static short toShort(byte[]b){
        return (short)((b[1]<<8)+(b[0]<<0));
    }
    public static byte[] read(RandomAccessFile rdf,int pos,int length)throws IOException{
        rdf.seek(pos);
        byte result[]=new byte[length];
        for(int i=0;i<length;i++){
            result[i]=rdf.readByte();
        }
        return result;
    }

    public static final HashMap<String, String> mFileTypes = new HashMap<String, String>();

    static {
        // images
        mFileTypes.put("52494646", "RIFF");
    }
    public static String getFileType(File f) {
       //System.out.println(getFileHeader(filePath));
       // System.out.println(mFileTypes.get(getFileHeader(filePath)));
        return mFileTypes.get(getFileHeader(f));
    }
    public static String getFileHeader(File f) {
        FileInputStream is = null;
        String value = null;
        try {
            is = new FileInputStream(f);
            byte[] b = new byte[4];
            /*
             * int read() 从此输入流中读取一个数据字节。 int read(byte[] b) 从此输入流中将最多 b.length
             * 个字节的数据读入一个 byte 数组中。 int read(byte[] b, int off, int len)
             * 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
             */
            is.read(b, 0, b.length);
            value = bytesToHexString(b);
        } catch (Exception e) {
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
        return value;
    }
    private static String bytesToHexString(byte[] src) {
        StringBuilder builder = new StringBuilder();//字符数组保存字符串
        if (src == null || src.length <= 0) {
            return null;
        }
        String hv;
        for (int i = 0; i < src.length; i++) {
            // 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写
            hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();//取得十六进制字符数
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);//连接数组一次加到上一数组后

        }

        return builder.toString();
    }
    public static void main(String[] args)throws Exception {
       // double[] testSong = new double[FFT.WINDOW_SIZE * 4];
        File file=new File("D:\\maltab\\MusicDatabase\\1.wav");
        RandomAccessFile rdf=null;
        rdf=new RandomAccessFile(file,"r");
        final String fileType = getFileType(file);
        if(fileType!="RTFF"&&(file.getName().endsWith(".wav"))&&toShort(read(rdf,22,2))==1&&toInt(read(rdf,24,4))==-21436&&toShort(read(rdf,34,2))==16)//判断后缀名
        {
            byte[] dataArry=toByteArray(file);

            short[] s=getShort(dataArry);
            double[] db=bytesToDouble(s);System.out.println(fft(db).length);  System.out.println(db.length);
            SongFingerprint testSongFingerprint = new SongFingerprint(db);

            List<Fingerprint> fingerprints = testSongFingerprint.getFingerprint();
            System.out.println("qq");
            for (Fingerprint fingerprint : fingerprints) {
                // save fingerprint to database or other

                List<ShazamHash> hashes=fingerprint.combineHash();
                for (ShazamHash hash : hashes) {
                hash.f1;
                    hash.f2;
                    hash.dt;
                    hash.id;
                    hash.offset;
                    // save hash to database or other
                }

            }

            PrintWriter out1=new PrintWriter(new FileWriter(new File("C:\\Users\\Administrator\\Desktop\\2.csv")));
            System.out.println(db.length);
        }
        else {
            System.out.println("This is not a wav");
        }
    }
}
